package com.liuyingxing.javaSpringCloudAccount.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.liuyingxing.entity.account.User;
import com.liuyingxing.entity.account.UserRole;
import com.liuyingxing.entity.common.Result;
import com.liuyingxing.entity.common.SearchBean;
import com.liuyingxing.entity.test.City;
import com.liuyingxing.javaSpringCloudAccount.dao.UserDao;
import com.liuyingxing.javaSpringCloudAccount.dao.UserRoleDao;
import com.liuyingxing.javaSpringCloudAccount.entity.UserVo;
import com.liuyingxing.javaSpringCloudAccount.service.TestFeignClient;
import com.liuyingxing.javaSpringCloudAccount.service.UserService;
import com.liuyingxing.javaSpringCloudAccount.util.MD5Util;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.vavr.control.Try;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * Created by IntelliJ IDEA.
 * @File UserServiceImpl.java
 * @Auth liuxing
 * @Date 2021/8/22 10:36
 * @Email liuxing997@foxmail.com
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserRoleDao userRoleDao;
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private TestFeignClient testFeignClient;

    //根据用户名和密码查询用户信息
    @Override
    public User getUserByUserNameAndPassword(String userName, String password) {
        return userDao.getUserByUserNameAndPassword(userName, MD5Util.getMD5(password));
    }

    //根据用户名查询用户信息
    @Override
    public User getUserByUserName(String userName) {
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserName(userName))
                .orElse(Collections.emptyList());
        return users.isEmpty() ? null : users.get(0);
    }

    //用户登录
    @Override
    public Result<User> login(User user) {
        User userTemp = userDao.getUserByUserNameAndPassword(user.getUserName(),
                MD5Util.getMD5(user.getPassword()));
        if (userTemp == null) {
            return new Result<User>(Result.ResultCode.FAILED.code, "Failed");
        }
        // TODO

        // 返回 result
        return new Result<User>(Result.ResultCode.SUCCESS.code, "Success",
                userTemp);
    }

    //用户登出
    @Override
    public void logout() {
        // TODO
    }

    //添加用户信息
    @Override
    @Transactional
    public Result<User> insertUser(User user) {
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserNameOrEmail(user.getEmail(), user.getUserName()))
                .orElse(Collections.emptyList());
        if (users.size() > 0) {
            return new Result<User>(Result.ResultCode.FAILED.code, "User Name or email is repeat.");
        }
        user.setCreateDate(LocalDateTime.now());
        user.setPassword(MD5Util.getMD5(user.getPassword()));
        userDao.insertUser(user);
        if (user.getRoles() != null) {
            user.getRoles().stream()
                    .forEach(item -> {
                        userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));
                    });
        }
        return new Result<User>(Result.ResultCode.SUCCESS.code, "Insert success", user);
    }

    //更新用户信息
    @Override
    @Transactional
    public Result<User> updateUser(User user) {
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserNameOrEmail(user.getEmail(), user.getUserName()))
                .orElse(Collections.emptyList());
        if (users.stream().filter(item -> item.getId() != user.getId()).count() > 0) {
            return new Result<User>(Result.ResultCode.FAILED.code, "User Name or email is repeat.");
        }
        userDao.updateUser(user);
        if (user.getRoles() != null && !user.getRoles().isEmpty()) {
            userRoleDao.deleteUserRoleByUserId(user.getId());
            user.getRoles().stream()
                    .forEach(item -> {
                        userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));
                    });
        }
        return new Result<User>(Result.ResultCode.SUCCESS.code, "Update success", user);
    }

    //根据ID获取用户信息
    @Override
    public User getUserById(int id) {
        return userDao.getUserById(id);
    }

    //删除用户信息
    @Override
    @Transactional
    public Result<Object> deleteUserById(int id) {
        userDao.deleteUserById(id);
        userRoleDao.deleteUserRoleByUserId(id);
        return new Result<Object>(Result.ResultCode.SUCCESS.code, "Delete success");
    }

    //分页查询用户信息
    @Override
    public PageInfo<User> getUsersBySearchBean(SearchBean searchBean) {
        searchBean.initSearchBean();
        PageHelper.startPage(searchBean.getCurrentPage(), searchBean.getPageSize());
        return new PageInfo<User>(Optional
                .ofNullable(userDao.getUsersBySearchVo(searchBean))
                .orElse(Collections.emptyList()));
    }

    //根据关键字查询用户信息
    @Override
    public List<User> getUsersByKeyWord(String keyWord) {
        SearchBean searchBean = new SearchBean();
        searchBean.setKeyword(keyWord);
        searchBean.initSearchBean();
        return Optional.ofNullable(userDao.getUsersBySearchVo(searchBean)).orElse(Collections.emptyList());
    }

    //根据ID获取用户信息（包括城市信息）
    @Override
    public UserVo getUserVoById(int id) {
        UserVo userVo = new UserVo();
        User user = userDao.getUserById(id);
        BeanUtils.copyProperties(user, userVo);
//        City city = restTemplate.getForObject(
//                "http://CLIENT-TEST/api/test/city/{cityId}",
//                City.class, 1890);
//        userVo.setCity(city);

        /*
         * - 熔断器策略配置
         * - 生产者抛出异常或停掉的情况，都会返回默认值
         */
        CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
                .failureRateThreshold(50)
                .waitDurationInOpenState(Duration.ofMillis(1000))
                .build();
        CircuitBreaker circuitBreaker = CircuitBreaker.of("circuitBreakerPloy", circuitBreakerConfig);
//        Try<City> circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
//                circuitBreaker,
//                () -> restTemplate.getForObject("http://CLIENT-TEST/api/test/city/{cityId}", City.class, 1890)
//        )).recover(Exception.class, new City());
        Try<City> circuitBreakerSupplier = Try.ofSupplier(CircuitBreaker.decorateSupplier(
                circuitBreaker,
                () -> testFeignClient.getCityByCityId(1890)
        )).recover(Exception.class, new City());
        userVo.setCity(circuitBreakerSupplier.get());
        return userVo;
    }
}
